package cn.lg.soar.gateway.handle;

import cn.lg.soar.common.data.msg.I18n;
import cn.lg.soar.common.exceptions.BaseAException;
import cn.lg.soar.common.model.HttpResult;
import cn.lg.soar.core.handler.ex.ErrorResult;
import cn.lg.soar.core.handler.ex.SoarExceptionHandler;
import cn.lg.soar.gateway.util.RequestUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
@Order(-1) // 保证优先级低于默认的ResponseStatusExceptionHandler,这样能拿到响应状态码
@Component
public class GlobalErrorExceptionHandler implements ErrorWebExceptionHandler {

    protected static final Logger LOGGER = LoggerFactory.getLogger(GlobalErrorExceptionHandler.class);

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        ServerHttpResponse response = exchange.getResponse();
        if (response.isCommitted()) {
            return Mono.error(ex);
        }
        ServerHttpRequest request = exchange.getRequest();
        // 将返回格式设为JSON
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        // 异常处理
        ErrorResult errorResult = SoarExceptionHandler.handle(ex, msg -> {
            LOGGER.warn("{} >>> {} >>> {}",
                    RequestUtils.getRemoteIp(request),
                    request.getURI().getPath(),
                    msg,
                    ex
            );
        });
        // 设置响应状态码
        response.setStatusCode(HttpStatus.valueOf(errorResult.getStatus()));
        // 改变请求响应返回行为
        return response.writeWith(Mono.fromSupplier(() -> {
            DataBufferFactory bufferFactory = response.bufferFactory();
            try {
                return bufferFactory.wrap(objectMapper.writeValueAsBytes(errorResult.getResult()));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
                return bufferFactory.wrap(new byte[0]);
            }
        }));
    }

    static {
        SoarExceptionHandler.register(NotFoundException.class, e -> {
            return new ErrorResult(404, HttpResult.fail(new BaseAException(400, I18n.build("服务未找到"))));
        });
    }

}
